package com.skydonkey.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.qiniu.common.QiniuException;
import com.skydonkey.config.RabbitConfig;
import com.skydonkey.config.RedisConfig;
import com.skydonkey.dao.*;
import com.skydonkey.es.ESVideoRepository;
import com.skydonkey.es.ESVideoService;
import com.skydonkey.es.Video;
import com.skydonkey.pojo.dto.VideoSampleDto;
import com.skydonkey.pojo.po.*;
import com.skydonkey.pojo.vo.*;
import com.skydonkey.service.VideoService;
import com.skydonkey.utils.ObjectMapperUtil;
import com.skydonkey.utils.QiniuUtils;
import com.skydonkey.utils.RedisUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
public class VideoServiceImpl implements VideoService {


    private static final Logger log = LoggerFactory.getLogger(VideoServiceImpl.class);

    private static final String R_WATCH_TIMES_KEY =
            RedisConfig.CACHE_NAMES_PREFIX + "wt_times" + RedisConfig.DECOLLATOR;

    @Autowired
    private ESVideoRepository ESVideoRepository;

    @Autowired
    private AccountFollowsMapper accountFollowsMapper;

    @Autowired
    private AccountInfoMapper accountInfoMapper;

    @Autowired
    private VideoCommentMapper videoCommentMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private QiniuUtils qiniuUtils;

    @Autowired
    private VideoCategoryMapper videoCategoryMapper;    //视频类别关联表

    @Autowired
    private CategoryMapper categoryDAO;    //视频类别信息

    @Autowired
    private VideoJoinedActivityMapper videoJoinedActivityMapper;  //视频参加的活动关联表

    @Autowired
    private VideoInfoMapper videoInfoMapper;  //视频基本信息


    @Autowired
    private VideoWatchHistoryMapper videoWatchHistoryMapper;    //观看历史记录

    @Autowired
    private VideoMyLikedMapper videoMyLikedMapper;  //视频-我的喜欢/点赞

    @Autowired
    private VideoMyFavoriteMapper videoMyFavoriteMapper;    //视频-我的收藏


    @Autowired
    private VideosWatchTimesMapper videosWatchTimesMapper;  // 视频-观看次数

    @Autowired
    private VideoSamplesMapper videoSamplesMapper;  //视频-缩略图

    @Autowired
    private AccountMapper accountMapper; //查询用户

    @Autowired
    private ESVideoService esVideoService;

    //获取所有的视频类别
    @Override
    public List<Category> getAllCategories() {
        return categoryDAO.selectAll();
    }

    //发布视频
    @Transactional
    @Override
    public Result<VideoPublishResp> publishVideo(VideoPublishReq req) throws QiniuException {
        VideoCategory videoCategory = new VideoCategory();  //视频-类别关联
        VideoInfo videoInfo = new VideoInfo();  //视频信息, 插入,拿到插入后的id
        VideoJoinedActivity videoJoinedActivity = new VideoJoinedActivity();
        BeanUtils.copyProperties(req, videoInfo);
        // 插入视频信息
        int insert = videoInfoMapper.insert(videoInfo);
        if (insert == 0) {
            return Result.failed(new VideoPublishResp()).setMsg("");
        }
        // 插入视频与类别关联信息
        videoCategory.setVideoId(videoInfo.getVideoId());
        for (Integer videoCategoryId : req.getVideoCategoryIds()) {
            videoCategory.setCategoryId(videoCategoryId);
            int insert1 = videoCategoryMapper.insert(videoCategory);
            if (insert1 == 0) {
                throw new RuntimeException("添加视频类别关联信息失败");
            }
        }
        // 插入视频与活动关联信息
        videoJoinedActivity.setVideoId(videoInfo.getVideoId());
        videoJoinedActivity.setActId(req.getChoosenVideoActivities());
        int insert2 = videoJoinedActivityMapper.insert(videoJoinedActivity);
        if (insert2 == 0) {
            throw new RuntimeException("添加视频与活动关联信息失败");
        }
//        通知七牛将mp4转换为flv, 并mq通知消费者轮询进度
//        String persistId = qiniuUtils.convertMp4ToFlv(videoInfo.getVideoKey());
//        log.info("persistId = " + persistId);
//        // 发送 persistId及其他属性 到消息队列, 让消费者去轮询结果, 更新flv的结果到数据库
//        VideoConversionDto videoConversionDto = new VideoConversionDto().setVideoId(1)
//                .setVideoKey(videoInfo.getVideoKey())
//                .setPersistId(persistId)
//                .setVideoOriginalFormat("mp4")
//                .setVideoTargetFormat("flv")
//                .setStatusCode(0);
//
        // 将视频信息存储到es
        Video video = new Video().setTitle(videoInfo.getTitle()).setVideoId(videoInfo.getVideoId());
        Video updateVideo = esVideoService.saveOrUpdateVideo(video);
        // 发送消息， 异步生成采样缩略图
        VideoSampleDto videoSampleDto = new VideoSampleDto()
                .setVideoId(videoInfo.getVideoId())
                .setUid(videoInfo.getUid())
                .setVideoKey(videoInfo.getVideoKey());
        rabbitTemplate.convertAndSend(
                RabbitConfig.VIDEO_SAMPLE_EXCHANGE_NAME,
                RabbitConfig.VIDEO_SAMPLE_ROUTING_KEY,
                videoSampleDto);


        return Result.success(new VideoPublishResp());
    }


    @Transactional
    @Override
    public DeleteVideoPublishedResp deletePublishedVideo(DeleteVideoPublishedReq req) {
        int re1 = videoInfoMapper.deleteVideoInfoMapper(req.getVideoId());
        if (re1 == 0) {
            return null;
        }
        int re2 = videoCategoryMapper.deleteVideoCategory(req.getVideoId());
        if (re2 == 0) {
            return null;
        }
        int re3 = videoJoinedActivityMapper.deleteByVideoId(req.getVideoId());
        if (re3 == 0) {
            return null;
        }
        return new DeleteVideoPublishedResp();

    }

    // 查找所有视频
    @Override
    public Page<VideoInfo> findAll(int pageNum, int pageSize) {
        // 开启分页功能
        PageHelper.startPage(pageNum, pageSize);
        // 调用Mapper方法，返回分页结果
        return videoInfoMapper.findAll();
    }

    @Override
    public VideoInfo getVideoInfoByVid(Long videoID) {
        return videoInfoMapper.findByVideoId(videoID);
    }

    //查找指定用户发布的视频
    @Override
    public Page<VideoInfo> findAllByUid(Long uid, int pageNum, int pageSize) {
        // 开启分页功能
        PageHelper.startPage(pageNum, pageSize);
        // 调用Mapper方法，返回分页结果
        return videoInfoMapper.findAllByUid(uid);
    }

    @Override
    public QueryPublishedVideoResp getPublishedVideo(QueryPublishedVideoReq req) {
        PageHelper.startPage(req.getPageNum(), req.getPageCount());
        Page<VideoInfo> videoInfos = videoInfoMapper.findByUid(req.getUid());
        List<VideoDetailsResp> list = new ArrayList<>();
        for (VideoInfo info : videoInfos) {
            VideoDetailsResp detail = getVideoDetail(info.getVideoId());
            list.add(detail);
        }
        return new QueryPublishedVideoResp().setVideos(list).setTotalCount(videoInfos.getTotal());
    }

    //按类别查找视频
    @Override
    public Page<VideoInfo> findVideoInfoByCategoryId(Integer categoryId, Integer pageNum, Integer pageSize) {
        // 开启分页功能
        PageHelper.startPage(pageNum, pageSize);
        // 调用Mapper方法，返回分页结果
        return videoInfoMapper.findByCategoryId(categoryId);
    }

    @Override
    public Page<VideoInfo> getMostLikedVideoInfo(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return videoInfoMapper.getMostLikedVideos();
    }

    //添加我的收藏
    @Override
    public int addVideoMyFavoriteVideo(AddVideoMyFavReq req) {
        VideoMyFavorite favorite = new VideoMyFavorite();
        BeanUtils.copyProperties(req, favorite);
        return videoMyFavoriteMapper.insertMyFavoriteVideo(favorite);
    }

    //删除我的收藏
    @Override
    public int deleteVideoMyFavorite(DeleteVideoMyFavReq req){
        VideoMyFavorite favorite = new VideoMyFavorite();
        BeanUtils.copyProperties(req, favorite);
        return videoMyFavoriteMapper.deleteMyFavoriteVideoById(favorite);
    }

    // 获取视频被收藏的次数
    @Override
    public Long getVideoMyFavoriteCount(Long videoId) {
        return videoMyFavoriteMapper.getVideoMyFavCount(videoId);
    }

    // 获取收藏的视频
    @Override
    public GetVideoMyFavResp getFavoriteVideos(GetVideoMyFavReq req) {
        Page<VideoMyFavorite> list = videoMyFavoriteMapper.getFavoriteVideosByUid(req.getUid());
        List<VideoDetailsResp> dataList = new ArrayList<>();
        for (VideoMyFavorite favorite : list){
            VideoDetailsResp data = getVideoDetail(favorite.getVideoId());
            data.setCreateTime(favorite.getCreateTime());
            dataList.add(data);
        }
        GetVideoMyFavResp resp = new GetVideoMyFavResp();
        resp.setVideos(dataList);
        return resp;

    }

    //添加我喜欢
    @Override
    public int addVideoMyLiked(AddVideoMyLikedReq req) {
        VideoMyLiked myLiked = new VideoMyLiked();
        BeanUtils.copyProperties(req, myLiked);
        return videoMyLikedMapper.insertMyLikedVideo(myLiked);
    }

    // 删除我喜欢
    @Override
    public int deleteVideoMyLiked(DeleteVideoMyLikedReq req) {
        VideoMyLiked myLiked = new VideoMyLiked();
        BeanUtils.copyProperties(req, myLiked);
        return videoMyLikedMapper.deleteMyLikedVideo(myLiked);
    }

    // 获取视频被“我喜欢”的次数
    @Override
    public Long getVideoMyLikedCount(Long videoId) {
        return videoMyLikedMapper.getVideoLikedCount(videoId);
    }

    // 获取我喜欢列表
    @Override
    public GetVideoMyLikedDetailsResp getVideoMyLikedDetails(GetVideoMyLikedDetailsReq req) {
        PageHelper.startPage(req.getPageNum(), req.getPageCount());
        Page<VideoMyLiked> videos = videoMyLikedMapper.getLikedVideosByUid(req.getUid());
        List<VideoDetailsResp> details = new ArrayList<>();
        for (VideoMyLiked liked : videos.getResult()) {
            VideoDetailsResp detail = this.getVideoDetail(liked.getVideoId());
            detail.setCreateTime(liked.getCreateTime());
            details.add(detail);
        }
        GetVideoMyLikedDetailsResp resp = new GetVideoMyLikedDetailsResp();
        resp.setVideos(details);
        return resp;
    }

    @Override
    public UpdatePermissionResp updateVideoPermission(UpdatePermissionReq req) {
        int re = videoInfoMapper.updatePermission(req.getPermission(), req.getVideoId());
        return re == 0 ? null : new UpdatePermissionResp();
    }

    // 添加历史记录
    @Override
    public int addVideoWatchHistory(AddVideoWatchHistoryReq req) {
        VideoWatchHistory history = new VideoWatchHistory();
        BeanUtils.copyProperties(req, history);
        videoWatchHistoryMapper.deleteWatchHistoryVideo(history);
        return videoWatchHistoryMapper.insertWatchHistoryVideo(history);
    }

    // 删除历史记录
    @Override
    public int deleteVideoWatchHistory(DeleteVideoWatchHistoryReq req) {
        VideoWatchHistory history = new VideoWatchHistory();
        BeanUtils.copyProperties(req, history);
        return videoWatchHistoryMapper.deleteWatchHistoryVideo(history);
    }

    @Override
    public GetVideoHistoryListResp getVideoWatchHistory(GetVideoHistoryListReq req) {
        PageHelper.startPage(req.getPageNum(), req.getPageCount());
        Page<VideoWatchHistory> history = videoWatchHistoryMapper.getWatchHistoryVideosByUid(req.getUid());
        GetVideoHistoryListResp resp = new GetVideoHistoryListResp();
        List<VideoDetailsResp> list = new ArrayList<>();
        for (VideoWatchHistory h : history.getResult()) {
            VideoDetailsResp detail = getVideoDetail(h.getVideoId());
            log.info("before: " + h.getCreateTime());
            detail.setCreateTime(h.getCreateTime());
            log.info("after: " + ObjectMapperUtil.toJSON(detail));
            list.add(detail);
        }
        resp.setVideos(list).setTotalCount(history.getTotal());
        return resp;
    }

    // 获取观看次数
    @Override
    public VideosWatchTimes getVideoWatchTimes(Long videoId) {
        Object o = redisUtils.get(R_WATCH_TIMES_KEY + Long.toString(videoId));
        if(o == null){
            return new VideosWatchTimes().setVideoId(videoId).setWatchTimes(0L);
        }
        Long times = Long.parseLong(o.toString());
        return new VideosWatchTimes().setVideoId(videoId).setWatchTimes(times);
    }

    // 观看次数+1
    @Override
    public Long addVideoWatchTimes(Long videoId) {
        Long incr = redisUtils.incr(R_WATCH_TIMES_KEY + Long.toString(videoId), 1);
        VideosWatchTimes times = new VideosWatchTimes().setVideoId(videoId).setWatchTimes(incr);
        if(incr == 1L){
            videosWatchTimesMapper.insert(times);
            return incr;
        }
        videosWatchTimesMapper.update(times);
        return incr;
    }

    //再返回获取当前是否是我喜欢的/我收藏的详细信息
    public VideoDetailsResp getVideoDetailWithUserLikedFav(Long uid, Long videoId){
        VideoDetailsResp resp = getVideoDetail(videoId);
        int liked = videoMyLikedMapper.isVideoLikedByUser(uid, videoId);
        int fav = videoMyFavoriteMapper.isVideoFavoritedByUser(uid, videoId);
        int followed = accountFollowsMapper.isFollowed(uid, resp.getVideoInfo().getUid());
        if(liked == 1){
            resp.setMyLiked(true);
        }
        if(fav == 1){
            resp.setMyFav(true);
        }
        if(followed == 1){
            resp.setFollowed(true);
        }
        return resp;
    }

    // 获取当前播放视频的详细信息
    @Override
    public VideoDetailsResp getVideoDetail(Long videoId){
        VideoInfo videoInfo = videoInfoMapper.findByVideoId(videoId);
        if (videoInfo == null) {
            return null;
        }
        Long likedCount = this.getVideoMyLikedCount(videoId);
        Long favoriteCount = this.getVideoMyFavoriteCount(videoId);
        VideosWatchTimes watchTimes = this.getVideoWatchTimes(videoId);
        Long watchCount = watchTimes == null ? 0 : watchTimes.getWatchTimes();
        Long commentTotalCount = videoCommentMapper.getTotalCount(videoId);
        List<String> categoryNames = videoCategoryMapper.selectCategoryNameByVideoId(videoId);
        VideoDetailsResp resp = new VideoDetailsResp();
        Account account = accountMapper.findById(videoInfo.getUid());
        AccountInfo accountInfo = accountInfoMapper.findById(videoInfo.getUid());

        resp.setVideoInfo(videoInfo)
                .setCategoryNames(categoryNames)
                .setLikedCount(likedCount)
                .setFavoritedCount(favoriteCount)
                .setWatchTimes(watchCount)
                .setCommentCount(commentTotalCount)
                .setAccountInfo(accountInfo)
                .setNickname(account.getNickname());

        return resp;
    }

    /**
     * 获取推荐视频列表，返回全站热度最高的视频
     *
     * @return
     */
    @Override
    public GetRecommendVideoDetailsResp getRecommendVideoDetail(Integer pageNum, Integer pageSize) {
        // 开启分页功能
        PageHelper.startPage(pageNum, pageSize);
        List<VideoDetailsResp> respList = new ArrayList<>();
        GetRecommendVideoDetailsResp resp = new GetRecommendVideoDetailsResp();
        Page<VideoInfo> videos = videoInfoMapper.getLatestPublishedVideos();
        for (VideoInfo video : videos) {
            VideoDetailsResp detail = getVideoDetail(video.getVideoId());
            if (detail == null) {
                continue;
            }
            respList.add(detail);
        }
        resp.setVideos(respList);
        // 调用Mapper方法，返回分页结果
        return resp;
    }

    @Override
    public GetVideoSamplesResp getVideoSamples(GetVideoSamplesReq req) {
        VideoInfo vi = videoInfoMapper.findByVideoId(req.getVideoId());

        List<VideoSamples> samples = videoSamplesMapper.getSamples(vi.getVideoKey());
        return new GetVideoSamplesResp().setSamples(samples);
    }

    @Override
    public CreateVideoCommentResp createComment(CreateVideoCommentReq req) {
        VideoComment videoComment = new VideoComment();
        BeanUtils.copyProperties(req, videoComment);
        int insert = videoCommentMapper.insert(videoComment);
        if(insert == 0){
            return null;
        }
        long commentId = videoComment.getCommentId();
        VideoComment comment = videoCommentMapper.findById(commentId);
        return new CreateVideoCommentResp().setVideoComment(comment);
    }

    @Override
    public GetVideoCommentResp getComment(GetVideoCommentReq req) {
        PageHelper.startPage(req.getPageNum(), req.getPageCount());
        Page<VideoComment> comments = videoCommentMapper.findByVideoId(req.getVideoId());
        return new GetVideoCommentResp()
                .setComment(comments)
                .setTotalCount(comments.getTotal());
    }

    @Override
    public SearchVideoResp searchVideoIdByTitle(SearchVideoReq req) {

        org.springframework.data.domain.Page<Video> searchedList = esVideoService.searchByTitle(req.getKey(), req.getPageNum(), req.getPageCount());
        List<VideoDetailsResp> videos = new ArrayList<>();
        for (Video video : searchedList) {
            VideoDetailsResp detail = getVideoDetail(video.getVideoId());
            videos.add(detail);
        }
        return new SearchVideoResp()
                .setTotalCount(searchedList.getTotalElements())
                .setVideos(videos);
    }



}
